﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Web.Security;
using System.DirectoryServices;
using System.Web.Hosting;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.DataAccess;
using Kiiro.ExceptionManagement;
using Kiiro.Validation.Validators.Entities;
using Kiiro.Model.Utility;

namespace Kiiro.Model
{
    public static class UserModel
    {
        /// <summary>
        /// Gets a list of active, not deleted, and not sharepoint account User entities
        /// </summary>
        /// <param name="userIds">The list of user ids to get.</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url</param>
        public static List<User> GetUsersByIds ( List<int> userIds, Guid siteCollectionId, string serverRelativeUrl )
        {
            if ( userIds == null || userIds.Count == 0 )
                throw new Exception ( "Cannot GetUsersByIds when userId collection to look for is null or empty" );

            return UserDA.Instance.GetUsersByIds ( userIds, siteCollectionId, serverRelativeUrl );
        }

        public static List<User> GetUsersNotOnTeam ( Guid siteCollectionId, string serverRelativeUrl )
        {
            List<TeamMember> members = TeamModel.GetTeamMembers ( siteCollectionId, serverRelativeUrl );

            // all users from the sharepoint groups (expanding any domain groups) that aren't already team members
            return GetUsersFromSPGroups ( siteCollectionId, serverRelativeUrl )
                .SelectMany<User, User> ( ExpandADGroup )
                    .Where ( delegate ( User user ) { return !members.Exists ( x => x.User.Login == user.Login ) && !user.IsSharePointAccount; } )
                        .DistinctLogin ( ( a, b ) => String.Compare ( a.Login, b.Login ) == 0 )     // does not really use this line but it has to be here for execution
                            .ToList ( );
        }

        public static List<User> GetUsersFromSPGroups ( Guid siteCollectionId, string serverRelativeUrl )
        {
            List<User> users = new List<User> ( );

            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                using ( SPWeb portalWeb = SPHelpers.IsProject ( web ) ? web.ParentWeb : web )
                {
                    foreach ( SPGroup group in portalWeb.AssociatedGroups )
                    {
                        foreach ( SPUser spUser in group.Users )
                        {
                            if ( !spUser.IsDomainGroup ||
                                ( spUser.IsDomainGroup && LicensingModel.HasUnlimitedUsers ( siteCollectionId, serverRelativeUrl ) ) )
                            {
                                List<KiiroGroup> userGroups = SPHelpers.GetUserGroups ( spUser.LoginName, siteCollectionId, serverRelativeUrl );

                                User user =
                                    UserModel.GetUserByLogin ( spUser.LoginName, siteCollectionId, serverRelativeUrl ) ??
                                    new User
                                    {
                                        Login = spUser.LoginName,
                                        FirstName = spUser.Name != null ? ( spUser.Name.Contains ( " " ) ? spUser.Name.Substring ( 0, spUser.Name.IndexOf ( " " ) ) : "" ) : spUser.LoginName,
                                        LastName = spUser.Name.Contains ( " " ) ? spUser.Name.Substring ( spUser.Name.IndexOf ( " " ) + 1 ) : "",
                                        Email = spUser.Email ?? "",
                                        Title = spUser.IsDomainGroup ? "Domain Group" : "User",
                                        IsADGroup = spUser.IsDomainGroup,
                                        IsAdministrator = userGroups.Contains ( KiiroGroup.PortalOwner )
                                    };

                                user.SPUserId = spUser.ID;

                                if ( !users.Exists ( x => x.Login == user.Login ) )
                                    users.Add ( user );
                            }
                        }
                    }
                }
            }

            return users;
        }

        public static User GetUserByLogin ( string login, Guid siteCollectionId, string serverRelativeUrl )
        {
            return UserDA.Instance.GetUserByLogin ( login, siteCollectionId, serverRelativeUrl );
        }

        public static User GetUserByEmail ( string email, Guid siteCollectionId, string serverRelativeUrl )
        {
            return UserDA.Instance.GetUserByEmail ( email, siteCollectionId, serverRelativeUrl );
        }

        public static User GetUserById ( int id, Guid siteCollectionId, string serverRelativeUrl )
        {
            return GetUsersByIds ( new List<int> { id }, siteCollectionId, serverRelativeUrl ).FirstOrDefault ( );
        }

        public static User GetOrCreateUser ( string loginName, Guid siteCollectionId, string serverRelativeUrl )
        {
            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                web.AllowUnsafeUpdates = true;
                SPUser spUser = web.EnsureUser ( loginName );
                web.AssociatedMemberGroup.AddUser ( spUser );
                web.AllowUnsafeUpdates = false;
                return GetOrCreateUser ( spUser.ID, siteCollectionId, serverRelativeUrl );
            }
        }

        public static User GetOrCreateUser ( int spUserId, Guid siteCollectionId, string serverRelativeUrl )
        {
            User user = null;

            if ( spUserId > 0 )
            {
                using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    User currentUser = GetUserByLogin ( web.CurrentUser.LoginName, siteCollectionId, serverRelativeUrl );
                    SPUser spUser = web.AllUsers.GetByID ( spUserId );

                    user = GetUserByLogin ( spUser.LoginName, siteCollectionId, serverRelativeUrl );

                    if ( user == null )
                    {
                        bool allowNonExplicitMembers = LicensingModel.HasUnlimitedUsers ( siteCollectionId, serverRelativeUrl );

                        List<KiiroGroup> userGroups = allowNonExplicitMembers ?
                            SPHelpers.GetUserGroups ( spUser.LoginName, siteCollectionId, serverRelativeUrl ) :
                            SPHelpers.GetUserGroupsExplicit ( spUser.LoginName, siteCollectionId, serverRelativeUrl );

                        bool owner = userGroups.Contains ( KiiroGroup.PortalOwner );
                        bool member = userGroups.Contains ( KiiroGroup.PortalMember );

                        if ( owner || member )
                        {
                            user = new User
                            {
                                Login = spUser.LoginName,
                                Email = spUser.Email,
                                FirstName = spUser.Name.Contains ( " " ) ? spUser.Name.Substring ( 0, spUser.Name.IndexOf ( " " ) ) : "",
                                LastName = spUser.Name.Contains ( " " ) ? spUser.Name.Substring ( spUser.Name.IndexOf ( " " ) + 1 ) : "",
                                IsADGroup = spUser.IsDomainGroup,
                                IsAdministrator = owner,
                                IsNonExplicitMember = allowNonExplicitMembers,
                                IsActive = true,
                                CreatedDate = DateTime.Now,
                                CreatedBy = currentUser,
                                ModifiedDate = DateTime.Now,
                                ModifiedBy = currentUser,
                                EditType = EditType.Created,
                                SPUserId = spUserId
                            };

                            LicensingModel.InvalidateActiveUsersCount ( siteCollectionId, serverRelativeUrl );

                            if ( LicensingModel.CanIncrementActiveUsersCount ( siteCollectionId, serverRelativeUrl ) )
                                user = currentUser != null ?
                                    Save ( user, siteCollectionId, serverRelativeUrl ) :
                                    ProvisionerSave ( user, siteCollectionId, serverRelativeUrl );
                            else
                                user = UserModel.GetUserByLogin ( Constants.Security.AD_AUTH_USERS_DOMAIN_GROUP_NAME, siteCollectionId, serverRelativeUrl );
                        }
                        else
                        {
                            user = UserModel.GetUserByLogin ( Constants.Security.AD_AUTH_USERS_DOMAIN_GROUP_NAME, siteCollectionId, serverRelativeUrl );
                        }
                    }
                }
            }

            return user;
        }

        public static List<User> GetActiveUsers ( Guid siteCollectionId, string serverRelativeUrl )
        {
            // all users from the sharepoint groups (expanding any domain groups) excluding any 'IsSharePointAccounts'
            return GetUsersFromSPGroups ( siteCollectionId, serverRelativeUrl )
                .Where ( delegate ( User user ) { return !user.IsSharePointAccount; } )
                    .SelectMany<User, User> ( UserModel.ExpandADGroup )
                        .Distinct ( ( x, y ) => String.Compare ( x.Login, y.Login ) == 0 )
                            .ToList ( );
        }

        public static List<User> GetAddToAllProjectsUsers ( Guid siteCollectionId, string serverRelativeUrl )
        {
            return UserDA.Instance.GetAddToAllProjectsUsers ( siteCollectionId, serverRelativeUrl );
        }

        public static User ProvisionerSave ( User user, Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                if ( !user.IsNonExplicitMember )
                {
                    if ( !PermissionsModel.SetPortalGroups ( siteCollectionId, serverRelativeUrl, user ) )
                    {
                        throw new Exception (
                            string.Format ( "An error occured while performing SPGroup management for {0} "
                                + "(SPUserId: {1}). Please check the log and try again.", user.FullName, user.SPUserId ) );
                    }
                }

                user = UserDA.Instance.ProvisionerSave ( user, siteCollectionId, serverRelativeUrl );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return user;
        }

        public static User Save ( User user, Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                if ( user != null && user.EditType != EditType.Unchanged )
                {
                    PermissionsModel.GetGlobalPermissionBitsForCurrentUser ( user, user.ModifiedBy, siteCollectionId, serverRelativeUrl, true );

                    if ( user.PermissionBitsUsers != null && user.PermissionBitsUsers.Count > 0 &&
                        ( user.PermissionBitsUsers [ 0 ] || user.PermissionBitsUsers [ 2 ] || user.PermissionBitsUsers [ 3 ] ) )
                    {
                        new UserValidator ( ).Validate ( user );

                        #region Additional Validation
                        if ( user.IsValid ( ) )
                        {
                            if ( user.EditType == EditType.Deleted )
                            {
                                //check if the user is the only project manager in projects before being deleted and if deleted ensure member is deleted from TeamMember List
                                bool canBeDeleted = true;
                                List<Project> projectsList = ProjectsModel.GetProjectsForUser ( siteCollectionId, serverRelativeUrl, user, new List<ProjectStatus> ( ) { ProjectStatus.Active, ProjectStatus.BeingPlanned, ProjectStatus.Closed } );
                                if ( projectsList != null )
                                {
                                    foreach ( Project project in projectsList )
                                    {
                                        if ( project.ProjectManagerIds.Count == 1 && project.ProjectManagerIds.Exists ( x => x == user.Id ) )
                                        {
                                            user.EditTypeMessage.Add ( new ValidationMessage ( ValidationSeverity.Validation, String.Format ( "\"{0}\" is the only project manager for project \"{1}\". To proceed please set another team member or a user to be a project manager for \"{2}\" then try deleting \"{3}\".", user.FullName, project.Title, project.Title, user.FullName ) ) );
                                            canBeDeleted = false;
                                            break;
                                        }
                                    }
                                    if ( canBeDeleted )
                                    {
                                        foreach ( Project project in projectsList )
                                        {
                                            TeamMember member = TeamModel.GetTeamMemberByUserId ( user.Id, project.SiteCollectionId, project.ServerRelativeWebUrl );

                                            if ( member != null )
                                            {
                                                member.EditType = EditType.Deleted;
                                                member.ModifiedBy = user.ModifiedBy;
                                                TeamModel.Save ( member, project.SiteCollectionId, project.ServerRelativeWebUrl );
                                            }
                                        }
                                    }
                                }
                            }
                            //Crop user profile image to be a square.
                            if ( user.PictureBytes != null )
                            {
                                user.PictureBytes = SPHelpers.CropImageToSquare ( user.PictureBytes );
                            }

                            // Do not allow duplicate Logins
                            if ( user.EditType == EditType.Created && user.PermissionBitsUsers [ 0 ] )
                            {
                                if ( DoesLoginExist ( user.Login, siteCollectionId, serverRelativeUrl ) )
                                    user.LoginMessage.Add ( new ValidationMessage ( ValidationSeverity.Validation, "Cannot add User. Requested Login already exists." ) );
                            }

                            if ( user.EditType != EditType.Created )
                            {
                                if ( user.EditType == EditType.Updated && user.PermissionBitsUsers [ 2 ] && user.Id == user.ModifiedBy.Id && user.ModifiedBy.IsAdministrator )
                                {
                                    if ( !user.IsAdministrator )
                                        user.IsAdministratorMessage.Add ( new ValidationMessage ( ValidationSeverity.Validation, "Administrators cannot remove the administrator role from themselves." ) );
                                }

                                if ( user.EditType == EditType.Deleted && user.PermissionBitsUsers [ 3 ] && user.ModifiedBy != null && user.Id == user.ModifiedBy.Id )
                                    user.EditTypeMessage.Add ( new ValidationMessage ( ValidationSeverity.Validation, "You cannot delete yourself." ) );
                            }
                        }
                        #endregion

                        if ( user.IsValid ( ) )
                        {
                            /* leaving update permission out of this check as a Kiiro User can update their profile, 
                                but only an Administrator can change group membership */
                            if ( user.PermissionBitsUsers [ 0 ] || user.PermissionBitsUsers [ 3 ] )
                            {
                                if ( !user.IsNonExplicitMember )
                                {
                                    PermissionsModel.SetPortalGroups ( siteCollectionId, serverRelativeUrl, user );
                                }
                            }

                            // get plain text password so we can send it in email
                            string cPassword = string.Empty;
                            if ( !string.IsNullOrEmpty ( user.Password ) )
                            {
                                cPassword = user.Password;
                                user.Password = HashPassword ( user.Password );
                            }

                            if ( user.EditType == EditType.Created || user.EditType == EditType.Updated )
                            {
                                if ( user.PermissionBitsUsers [ 0 ] || user.PermissionBitsUsers [ 2 ] )
                                    user = UserDA.Instance.Save ( user, siteCollectionId, serverRelativeUrl );
                                else
                                    throw new KiiroUnauthorizedAccessException ( "Saving User Failed: Current User is not allowed to Create/Update User object." );

                                #region EmailNotification
                                if ( user.EditType == EditType.Created && user.ReceiveEmailNotification )
                                {
                                    using ( SPSite site = new SPSite ( user.SiteCollectionId ) )
                                    {
                                        string [ ] args;

                                        if ( user.IsFormsUser )
                                        {
                                            string url = EmailModel.Instance.FixUrlForUserZone ( site.Url, user );

                                            args = new string [ ]
                                                {
                                                    user.FullName,
                                                    user.Login,
                                                    cPassword,
                                                    url
                                                };
                                            EmailModel.Instance.SendNotificationEmail ( EmailModel.EmailType.FormsUserWelcome, user.Email, args, user.ModifiedBy );
                                        }
                                        else
                                        {
                                            args = new string [ ]
                                                {
                                                    user.FullName,
                                                    site.Url
                                                };
                                            EmailModel.Instance.SendNotificationEmail ( EmailModel.EmailType.Welcome, user.Email, args, user.ModifiedBy );
                                        }
                                    }
                                }
                                #endregion
                            }
                            else if ( user.EditType == EditType.Deleted )
                            {
                                if ( user.PermissionBitsUsers [ 3 ] )
                                {
                                    if ( user.Id != default ( int ) )
                                        user = UserDA.Instance.Save ( user, siteCollectionId, serverRelativeUrl );
                                }
                                else
                                    throw new KiiroUnauthorizedAccessException ( "Deleting User Failed: Current User is not allowed to Delete User object." );
                            }
                        }
                    }
                    else
                        throw new KiiroUnauthorizedAccessException ( "Updating User Failed: Access Denied." );
                }
            }
            catch ( SPException spEx )
            {
                if ( spEx.ErrorCode == -2130575223 )
                {
                    user.IsActiveMessage.Add ( new ValidationMessage ( ValidationSeverity.Validation, "Cannot activate User. Activating User will exceed User Limit." ) );
                }
                else
                {
                    ExceptionManager.HandleException ( spEx, true );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return user;
        }

        public static User UpdateStatusMessage ( User user, Guid siteCollectionId, string serverRelativeUrl )
        {
            if ( PermissionsModel.CanUserUpdateThemselves ( user.Id, user.Login, user.Id ) )
            {
                if ( user.EditType == EditType.Updated )
                {
                    UserDA.Instance.UpdateStatusMessage ( user, siteCollectionId, serverRelativeUrl );
                }
            }
            else
                throw new KiiroUnauthorizedAccessException ( "Updating User Status Failed: Access Denied." );

            return user;
        }

        public static User UpdateUserProjectIds ( User user, Guid siteCollectionId, string serverRelativeUrl, int projectId, EditType editType )
        {
            // determine if update is required
            if ( editType == EditType.Deleted && user.ProjectIds.Contains ( projectId ) )
            {
                user.ProjectIds.Remove ( projectId );
                user.EditType = EditType.Updated;
                UserDA.Instance.Save ( user, siteCollectionId, serverRelativeUrl );
            }
            else if ( ( editType == EditType.Created || editType == EditType.Updated ) && !user.ProjectIds.Contains ( projectId ) )
            {
                user.ProjectIds.Add ( projectId );
                user.EditType = EditType.Updated;
                UserDA.Instance.Save ( user, siteCollectionId, serverRelativeUrl );
            }

            return user;
        }

        private static bool DoesLoginExist ( string login, Guid siteCollectionId, string serverRelativeUrl )
        {
            User user = UserDA.Instance.GetUserByLogin ( login, siteCollectionId, serverRelativeUrl );
            return user != null && user.Login.ToLower ( ) == login.ToLower ( ).Replace ( "kiiromembership:", "" );
        }

        /// <summary>
        /// Take a password in plain-text and return a SHA1 hashed value back
        /// </summary>
        internal static string HashPassword ( string password )
        {
            System.Security.Cryptography.HMACSHA1 hash = new System.Security.Cryptography.HMACSHA1 ( );
            hash.Key = HexToByte ( Constants.Security.HK );
            return Convert.ToBase64String ( hash.ComputeHash ( Encoding.Unicode.GetBytes ( password ) ) );
        }

        /// <summary>
        /// Convert a hex string to a byte array
        /// </summary>
        private static byte [ ] HexToByte ( string hexString )
        {
            byte [ ] returnBytes = new byte [ hexString.Length / 2 ];
            for ( int i = 0; i < returnBytes.Length; i++ )
                returnBytes [ i ] = Convert.ToByte ( hexString.Substring ( i * 2, 2 ), 16 );
            return returnBytes;
        }

        public static void ResetAndEmailPassword ( string login, Guid siteCollectionId, string serverRelativeUrl )
        {
            Membership.Provider.ResetPassword ( login, "" );
        }

        public static bool ConfirmCurrentPassword ( string login, string password )
        {
            return Membership.Provider.ValidateUser ( login, password );
        }

        public static User GetADUser ( string userLogin )
        {
            User adUser = new User ( );

            using ( HostingEnvironment.Impersonate ( ) )
            {
                try
                {
                    string [ ] login = userLogin.Contains ( "\\" ) ? userLogin.Split ( "\\".ToCharArray ( ), StringSplitOptions.RemoveEmptyEntries ) : userLogin.Split ( ":".ToCharArray ( ), StringSplitOptions.RemoveEmptyEntries ); //Split Domain and Login
                    string domain = null;
                    string name = null;

                    if ( login.Length > 1 )
                    {
                        domain = login [ 0 ];
                        name = login [ 1 ];
                    }
                    else
                    {
                        name = login [ 0 ];
                    }

                    DirectoryEntry adRoot = string.IsNullOrEmpty ( domain ) ? new DirectoryEntry ( "" ) : new DirectoryEntry ( "LDAP://" + domain, null, null, AuthenticationTypes.Secure );
                    DirectorySearcher searcher = new DirectorySearcher ( adRoot );
                    searcher.SearchScope = SearchScope.Subtree;
                    searcher.ReferralChasing = ReferralChasingOption.All;
                    searcher.PropertiesToLoad.AddRange ( new string [ ] { "fullname" } );
                    searcher.Filter = string.Format ( "(&(ObjectClass={0})(sAMAccountName={1}))", "user", name );
                    SearchResult result = null;

                    try
                    {
                        result = searcher.FindOne ( );
                    }
                    catch ( Exception ex )
                    {
                        ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                    }

                    if ( result == null )
                    {
                        searcher.Filter = string.Format ( "(&(ObjectClass={0})(displayname={1}))", "user", name );
                        try
                        {
                            result = searcher.FindOne ( );
                        }
                        catch ( Exception ex )
                        {
                            ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                        }
                    }

                    if ( result == null )
                    {
                        searcher.Filter = "(CN=" + name + ")";
                        try
                        {
                            result = searcher.FindOne ( );
                            adUser.IsADGroup = true;
                        }
                        catch ( Exception ex )
                        {
                            ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                        }
                    }

                    if ( result != null )
                    {
                        DirectoryEntry directoryEntry = result.GetDirectoryEntry ( );

                        domain = adRoot.Name.Substring ( adRoot.Name.IndexOf ( "=" ) + 1 );
                        adUser.Login = directoryEntry.Properties [ "sAMAccountName" ].Value != null ? domain.ToUpper ( ) + "\\" + directoryEntry.Properties [ "sAMAccountName" ].Value.ToString ( ) : string.Empty;
                        adUser.FirstName = directoryEntry.Properties [ "givenName" ].Value != null ? directoryEntry.Properties [ "givenName" ].Value.ToString ( ) : string.Empty;
                        adUser.LastName = directoryEntry.Properties [ "sn" ].Value != null ? directoryEntry.Properties [ "sn" ].Value.ToString ( ) : string.Empty;
                        adUser.Email = directoryEntry.Properties [ "mail" ].Value != null ? directoryEntry.Properties [ "mail" ].Value.ToString ( ) : string.Empty;
                        adUser.Title = directoryEntry.Properties [ "title" ].Value != null ? directoryEntry.Properties [ "title" ].Value.ToString ( ) : string.Empty;
                        adUser.PhoneNumber = directoryEntry.Properties [ "telephoneNumber" ].Value != null ? directoryEntry.Properties [ "telephoneNumber" ].Value.ToString ( ) : string.Empty;
                        adUser.CompanyName = directoryEntry.Properties [ "company" ].Value != null ? directoryEntry.Properties [ "company" ].Value.ToString ( ) : string.Empty;
                    }
                    else
                    {
                        domain = domain ?? Environment.MachineName;
                        DirectoryEntry localMachine = new DirectoryEntry ( "WinNT://" + domain );

                        try
                        {
                            DirectoryEntry user = localMachine.Children.Find ( name );

                            if ( user != null )
                            {
                                adUser = new User ( );
                                adUser.Login = domain.ToUpper ( ) + "\\" + user.Properties [ "Name" ].Value.ToString ( );
                            }
                        }
                        catch ( Exception ex )
                        {
                            ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                        }
                    }
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
            }

            return adUser;
        }

        public static List<User> ExpandADGroup ( User user )
        {
            List<User> users = new List<User> { user };

            try
            {
                if ( user.IsADGroup )
                {
                    users = new List<User> ( );

                    using ( HostingEnvironment.Impersonate ( ) )
                    {
                        string [ ] login = user.Login.Split ( "\\".ToCharArray ( ), StringSplitOptions.RemoveEmptyEntries );
                        string domainName = login.Length > 1 ? login [ 0 ] : null;
                        string groupName = login.Length > 1 ? login [ 1 ] : login [ 0 ];

                        DirectoryEntry rootEntry = string.IsNullOrEmpty ( domainName ) ?
                            new DirectoryEntry ( "" ) : new DirectoryEntry ( "LDAP://" + domainName, null, null, AuthenticationTypes.Secure );

                        DirectorySearcher searcher = new DirectorySearcher ( rootEntry, "(CN=" + groupName + ")" );
                        searcher.SearchScope = SearchScope.Subtree;
                        searcher.ReferralChasing = ReferralChasingOption.All;
                        searcher.PropertiesToLoad.AddRange ( new string [ ] { "member" } );
                        
                        SearchResultCollection searchResults = searcher.FindAll ( );
                        foreach ( SearchResult result in searchResults )
                        {
                            ResultPropertyCollection resultProperties = result.Properties;

                            foreach ( Object memberObj in resultProperties [ "member" ] )
                            {
                                DirectoryEntry memberEntry = new DirectoryEntry ( "LDAP://" + memberObj );
                                PropertyCollection memberProperties = memberEntry.Properties;

                                domainName = rootEntry.Name.Substring ( rootEntry.Name.IndexOf ( "=" ) + 1 );

                                User groupUser = new User
                                {
                                    Login = memberProperties [ "sAMAccountName" ].Value != null ? domainName.ToUpper ( ) + "\\" + memberProperties [ "sAMAccountName" ].Value.ToString ( ) : string.Empty,
                                    FirstName = memberProperties [ "givenName" ].Value != null ? memberProperties [ "givenName" ].Value.ToString ( ) : string.Empty,
                                    LastName = memberProperties [ "sn" ].Value != null ? memberProperties [ "sn" ].Value.ToString ( ) : string.Empty,
                                    Email = memberProperties [ "mail" ].Value != null ? memberProperties [ "mail" ].Value.ToString ( ) : string.Empty,
                                    Title = memberProperties [ "title" ].Value != null ? memberProperties [ "title" ].Value.ToString ( ) : string.Empty,
                                    PhoneNumber = memberProperties [ "telephoneNumber" ].Value != null ? memberProperties [ "telephoneNumber" ].Value.ToString ( ) : string.Empty,
                                    CompanyName = memberProperties [ "company" ].Value != null ? memberProperties [ "company" ].Value.ToString ( ) : string.Empty
                                };

                                users.Add ( groupUser );
                            }
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                Logging.LoggingManager.LogMessage ( "ERROR", "Error retrieving Active Directory information for group: " + user.Login );
                ExceptionManagement.ExceptionManager.HandleException ( ex, false );
            }

            return users;
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.Model/UserModel.cs $
 * 
 * 52    2/08/10 5:04p Camerons
 * 
 * 51    1/25/10 1:17p Camerons
 * 
 * 50    1/12/10 12:03p Camerons
 * 
 * 49    15/12/09 11:49a Adamw
 * Case 418 added overloaded delegateComparer
 * 
 * 48    12/02/09 2:50p Camerons
 * 
 * 47    26/11/09 10:35a Camerons
 * 
 * 46    23/11/09 3:47p Camerons
 * 
 * 45    17/11/09 6:46p Camerons
 * 
 * 44    16/11/09 6:09p Camerons
 * 
 * 43    6/11/09 8:55p Camerons
 * 
 * 42    6/11/09 3:17p Camerons
 * 
 * 41    29/10/09 2:55p Camerons
 * 
 * 40    29/10/09 2:17p Camerons
 * 
 * 39    29/10/09 1:06p Camerons
 * remove additional validation messages during save that deal with
 * IsActive and IsAdministrator
 * 
 * 38    28/10/09 10:32p Camerons
 * 
 * 37    28/10/09 1:41p Camerons
 * 
 * 36    28/10/09 11:01a Camerons
 * 
 * 35    27/10/09 2:48p Shafia
 * check if the user is the only project manager in projects before being
 * deleted and if deleted ensure member is deleted from TeamMember List
 * 
 * 34    19/10/09 12:51p Shafia
 * 
 * 33    15/10/09 12:17p Camerons
 * Fix GetOrCreateUser (login, ...)
 * 
 * 32    15/10/09 9:34a Camerons
 * 
 * 31    9/10/09 4:25p Camerons
 * Repaired some code for AD Lookup
 * 
 * 30    8/10/09 6:41p Camerons
 * Updates for Server License
 * 
 * 29    10/07/09 6:06p Adamw
 * 
 * 28    10/07/09 6:00p Adamw
 * added check for isActive or isDeleted on GetOrCreateUser, access denied
 * if either is true
 * 
 * 27    7/10/09 2:38p Camerons
 * Case #283: When deleting user, clear the User.ProjectIds and remove the
 * SPUser from any Kiiro SPGroups
 * 
 * 26    6/10/09 10:25a Stefanf
 * 
 * 25    5/10/09 1:56p Camerons
 * Implement re-adding of the guest account code to the PortalProvisioner
 * and UserModel. Enable and disable various UI elements for guest account
 * 
 * 24    5/10/09 1:07p Camerons
 * 
 * 23    5/10/09 11:07a Camerons
 * RE: Create user on demand, checks for HasUnlimitedUser before creating
 * 
 * 22    1/10/09 3:28p Camerons
 * Load Expanded ADGroups into drop down on NewTeamMember. Create user on
 * demand if selected user doesn't exist.
 * 
 * 21    30/09/09 1:08p Camerons
 * Implementing UserModel.GetOrCreateUser(). 
 * 
 * 20    29/09/09 3:52p Camerons
 * Changes involving AllUsers.aspx and SPGroups. AllUsers page now
 * displays the recoreds from the SPGroups instead of Kiiro user list.
 * Allows for security to be managed for the SharePoint admin screens. 
 * 
 * 19    29/09/09 2:19p Camerons
 * Implementing User.SPUserId
 * 
 * 18    28/09/09 3:38p Camerons
 * 
 * 17    28/09/09 10:13a Camerons
 * 
 * 16    25/09/09 1:48p Camerons
 * 
 * 15    23/09/09 4:46p Camerons
 * Fixed some old code dealing with User.ManageProjects
 * 
 * 14    22/09/09 6:03p Camerons
 * Code changes to support creating user on demand - version 1.1.x.x
 * 
 * 13    21/09/09 3:30p Camerons
 * First batch of changes for 1.1.x.x - Security groups update
 * 
 * 12    10/09/09 7:15p Camerons
 * 
 * 11    9/04/09 10:27a Stefanf
 * 
 * 10    3/09/09 1:22p Camerons
 * Added call to overloaded UserDA.Save method for PortalProvider
 * 
 * 9     9/02/09 10:43a Stefanf
 * 
 * 8     17/08/09 10:29a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/